/*
 * File: TurtleGraphics.java
 * -------------------------
 * This file represents the starter file for the TurtleGraphics application.
 * Your job in Assignment #4 is to complete this application by implementing
 * the execute and replaceAction methods.  You also need to implement the
 * TurtleScanner class in the file TurtleScanner.java.
 */

import acm.program.*;
import acm.util.*;

public class TurtleGraphics extends GraphicsProgram {

/* Constants to set the application size */
	public static final int APPLICATION_WIDTH = 1000;
	public static final int APPLICATION_HEIGHT = 600;

/*
 * Initializes the application.  Programs call the init() method before
 * laying out the components in the window and the run() method after the
 * layout is complete.  This application is driven entirely by events
 * generated by the buttons and menus and does not need a run() method.
 */
	public void init() {
		turtle = new GTurtle();
		add(turtle);
		ui = new TurtleGraphicsUI();
		ui.start();
	}

/*
 * Executes a turtle program, which consists of a string of commands.
 * Each command consists of a single letter, optionally followed by an
 * integer.  The commands you must implement for this assignment are
 *
 *    F#       Moves forward the specified number of pixels (default = 50)
 *    L#       Turn left the specified number of degrees (default = 90)
 *    R#       Turn right the specified number of degrees (default = 90)
 *    U        Raise the pen so that moving no longer draws a line
 *    D        Lower the pen to resume line drawing
 *    X#{cmds} Execute the block of commands the specified number of times
 */
	public void execute(String str) {
		int timesToRepeat = 0;
		TurtleTokenizer tokenizer = new TurtleTokenizer(str);
		while(tokenizer.hasMoreTokens()){
			String token = tokenizer.nextToken();
			if(token.equalsIgnoreCase("")){
				break;
			}
			char id = token.charAt(0); // This character is used to identify the command using the first letter and it makes the condition in the if-else construct smaller.
			int value = 0;
			if(id == 'F'){
				if(token.length() > 1){
					value = Integer.parseInt(token.substring(1));
					turtle.forward(value);
				}
				else if(token.length() == 1){
					turtle.forward(defaultMove);
				}
			}
			if(id == 'L'){
				if(token.length() > 1){
					value = Integer.parseInt(token.substring(1));
					turtle.left(value);
				}
				else if(token.length() == 1){
					turtle.left(defaultAngle);
				}
			}
			if(id == 'R'){
				if(token.length() > 1){
					value = Integer.parseInt(token.substring(1));
					turtle.right(value);
				}
				else if(token.length() == 1){
					turtle.right(defaultAngle);
				}
			}
			if(id == 'U'){
				turtle.penUp();
			}
			if(id == 'D'){
				turtle.penDown();
			}
			if(id == 'X'){
				timesToRepeat = Integer.parseInt(token.substring(1));
			}
			if(id == '{'){
				token = token.substring(1, token.length() - 1);
				for(int i = 0; i < timesToRepeat; i++){
					execute(token); // Recursion.
				}
			}
			if(id == 'M'){
				if(token.length() > 1){
					value = Integer.parseInt(token.substring(1));
					defaultMove = value;
				}
			}
			if(id == 'A'){
				if(token.length() > 1){
					value = Integer.parseInt(token.substring(1));
					defaultAngle = value;
				}
			}
			if(id == 'H'){
				turtle.hideTurtle();
			}
			if(id == 'S'){
				turtle.showTurtle();
			}
		}
	}

/*
 * Implements the Replace button action, which replaces all instances of a
 * pattern string in the current file with a replacement string.  The
 * pattern and replacement strings are taken from the replacement field in
 * the user interface, where they appear as pattern->replacement.   
 */
	public void replaceAction() {
		int currentPosition = 0;
		String pattern = "";
		String replacement = "";
		String replaceStr = ui.getReplacementField();
		replaceStr = toUpperCase(replaceStr);
		replaceStr = removeAllWhitespace(replaceStr);
		int errorVar = 0;
		for(int i = 0; i < replaceStr.length(); i++){
			if(replaceStr.charAt(i) == '-' && replaceStr.charAt(i + 1) == '>'){
				errorVar++;
			}
		}
		if(errorVar != 1){
			throw new ErrorException("Missing or Extra \"->\".");
		}
		for(int i = currentPosition; i < replaceStr.length(); i++){
			if(Character.isLetterOrDigit(replaceStr.charAt(i))){
				pattern += replaceStr.charAt(i);
				currentPosition++;
			}
			if(replaceStr.charAt(i) == '-' && replaceStr.charAt(i + 1) == '>'){
				currentPosition++;
				currentPosition++;
				break;
			}
		}
		for(int i = currentPosition; i < replaceStr.length(); i++){
			if(Character.isLetterOrDigit(replaceStr.charAt(i))){
				replacement += replaceStr.charAt(i);
				currentPosition++;
			}
		}
		String oldProgramText = ui.getProgramText();
		String newProgramText = removeAllOccurrences(oldProgramText, pattern, replacement);	
		ui.setProgramText(newProgramText);
	}
	
	private String removeAllWhitespace(String str){
		String result = "";
		for(int i = 0; i < str.length(); i++){
			char x = str.charAt(i);
			if(x != ' ' && x != '\t' && x != '\n'){
				result += x;
			}
		}
		return result;
	}
	
	private String toUpperCase(String str){
		String result = "";
		for(int i = 0; i < str.length(); i++){
			char ch = Character.toUpperCase(str.charAt(i));
			result += ch;
		}
		return result;
	}
	
	private String removeAllOccurrences(String str, String oldText, String newText){
		String result = "";
		int resultChecker = 0;
		char extra = ' ';
		for(int i = 0; i < str.length(); i++){
			char ch = str.charAt(i);
			for(int j = 0; j < oldText.length(); j++){
				if(i < str.length() && oldText.charAt(j) == str.charAt(i)){
					resultChecker++;
					if(i + 1 < str.length()){
						extra = str.charAt(i + 1);
					}
					i++;
				}
				else{
					result += ch;
					break;
				}
			}
			if(resultChecker == oldText.length()){
				result += newText;
				result += extra;
				resultChecker = 0;
				
			}
		}
		return result;
	}

/* Private instance variables */
	
	private int defaultMove = 50;
	private int defaultAngle = 90;
	private GTurtle turtle;         /* The GTurtle object        */
	private TurtleGraphicsUI ui;    /* The user-interface object */
}
